package bet

import (
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"math"
	nhttp "net/http"
	"strings"
	"time"
	"wzgames/internal/api/bindo"
	"wzgames/internal/client"
	"wzgames/internal/constant"
	"wzgames/internal/gvalidator"
	"wzgames/internal/model/mcomm"
	"wzgames/internal/model/statement"
	"wzgames/internal/response"
	"wzgames/internal/version"
	"wzgames/pkg/logger"
	"wzgames/pkg/server/http"
	"wzgames/pkg/server/http/types"
	"wzgames/pkg/utils/dateutil"
	"wzgames/pkg/utils/stringutil"
)

func RegisterRoute(pGroup *gin.RouterGroup) {
	bizGroup := pGroup.Group("bet")
	http.MethodMapper(bizGroup, types.POST)(statementFn())
}

var statementFn = func() (string, func(c *gin.Context)) {
	uri := fmt.Sprintf("/statement")
	return uri, func(c *gin.Context) {
		resp := types.Response{}
		var params bindo.BetStatementBind
		if err := c.ShouldBind(&params); err != nil {
			resp.Code = response.ErrBadRequest
			c.JSON(nhttp.StatusOK, resp)
			return
		}
		if len(params.AgtCode) > 15 || !gvalidator.IsAlphaNumeric(params.AgtCode) {
			resp.Code = response.ErrBadRequest
		} else if !gvalidator.IsNumeric(params.Stamp) || !gvalidator.CheckTimestamp(params.Stamp) {
			resp.Code = response.ErrBadRequest
		} else if !gvalidator.IsAlphaNumeric(params.HashVal) || len(params.HashVal) > 64 {
			resp.Code = response.ErrSign
		}
		if resp.Code != 0 {
			c.JSON(nhttp.StatusOK, resp)
			return
		}
		var vidx uint64
		var st, et int64
		vidx, _ = stringutil.ToUint64(params.VIdx, 0)
		pageSize, _ := stringutil.ToInt32(params.PerPage, 100)
		if vidx > math.MaxInt64 || pageSize > constant.MaxStmPerSize || pageSize < constant.MinStmPerSize {
			resp.Code = response.ErrBadRequest
		} else if params.Start != "" {
			if len(params.Start) != 10 || len(params.End) != 10 {
				resp.Code = response.ErrDateRange
			} else {
				st, _ = stringutil.ToInt64(params.Start, 0)
				et, _ = stringutil.ToInt64(params.End, 0)
				if st <= 0 || et <= 0 || st > et || st < version.CreateStamp || et > st+constant.ThreeMonthsInSecs || et > dateutil.UnixSecs()+dateutil.Hour {
					resp.Code = response.ErrDateRange
				}
			}
		}

		if resp.Code != 0 {
			c.JSON(nhttp.StatusOK, resp)
			return
		}

		agtId, err := gvalidator.DecodeAgentID(params.AgtCode)
		if err != nil {
			logger.Error("[API] bet statement get fail on decode agent code", zap.String("AgtCode", params.AgtCode))
			resp.Code = response.ErrBadRequest
			c.JSON(nhttp.StatusOK, resp)
			return
		}

		var si strings.Builder
		si.WriteString(params.AgtCode)
		si.WriteString(params.PerPage)
		si.WriteString(params.Start)
		si.WriteString(params.End)
		si.WriteString(params.VIdx)
		si.WriteString(params.Stamp)
		req := &mcomm.NormalSignCheck{
			AgtID:    agtId,
			Combine:  si.String(),
			Sign:     params.HashVal,
			ClientIP: c.ClientIP(),
		}
		reply := &mcomm.CodeRet{}
		rpcCtx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
		err = client.GetCatClient().Call(rpcCtx, "NormalSignAuth", req, reply)
		cancelFn()
		if err != nil {
			resp.Code = response.ErrInternal
			logger.Error("[API] bet statement sign auth check fail", zap.String("AgtCode", params.AgtCode), zap.Error(err))
		} else {
			resp.Code = int16(reply.Code)
			if reply.Code == 0 {
				stmReq := &statement.StmReq{
					AgtId: agtId,
					Per:   pageSize,
					Start: st * 1000,
					End:   et * 1000,
					VIdx:  vidx,
				}
				stmReply := &statement.StmRes{}
				rpcCtx, cancelFn = context.WithTimeout(context.Background(), 30*time.Second)
				err = client.GetBetTowerClient().Call(rpcCtx, "QueryStatements", stmReq, stmReply)
				cancelFn()
				if err != nil {
					resp.Code = response.ErrInternal
					logger.Error("[API] query statements fail on call QueryStatements", zap.String("AgtCode", params.AgtCode), zap.String("Ver", params.VIdx),
						zap.String("Per", params.PerPage), zap.String("Start", params.Start), zap.String("End", params.End), zap.Error(err))
				} else {
					resp.Code = int16(stmReply.Code)
					if resp.Code == 0 {
						c.Data(200, constant.JsonContentType, stmReply.Data)
						return
					}
				}
			}
		}
		if resp.Code == 0 {
			resp.Code = 200
		}

		c.JSON(nhttp.StatusOK, resp)
		return
	}
}
